Skip to content

Comments

feat(pnpm): add rtk pnpm [run] <script> with smart filter routing#232

Open
denneulin wants to merge 1 commit intortk-ai:masterfrom
denneulin:feat/pnpm
Open

feat(pnpm): add rtk pnpm [run] <script> with smart filter routing#232
denneulin wants to merge 1 commit intortk-ai:masterfrom
denneulin:feat/pnpm

Conversation

@denneulin
Copy link

Summary

  • Add rtk pnpm run <script> and rtk pnpm <script> shorthand with smart routing to specialized filters
  • Strip pnpm boilerplate (lifecycle headers, script echo, "Done in Xs", ELIFECYCLE errors, progress bars)
  • Two-tier script routing: static name matching (test, lint, typecheck, vitest, prettier, format) +
    package.json auto-detection for custom scripts (e.g., test:e2e → detects playwright test
    PlaywrightParser)
  • Promote filter_tsc_output, filter_generic_lint, extract_test_summary to pub(crate) for cross-module
    reuse

Token Savings

Script Route Expected Savings
pnpm [run] test (vitest) VitestParser 90%+
pnpm [run] typecheck (tsc) filter_tsc_output 80%+
pnpm [run] lint (eslint) filter_generic_lint 80%+
pnpm [run] prettier --check filter_prettier_output 70%+
pnpm [run] test:e2e (playwright) PlaywrightParser 80%+
pnpm [run] build (unrouted) Boilerplate strip only 30-50%

How It Works

  • rtk pnpm run testPnpmCommands::Runrun_script("test") → boilerplate strip → TestRunner filter
  • rtk pnpm testPnpmCommands::Otheris_pnpm_script("test")run_script("test")
  • rtk pnpm test:e2e → reads package.json → detects playwright test → PlaywrightParser
  • rtk pnpm store pruneis_pnpm_script("store") = false → passthrough

Test plan

  • 25 new unit tests (boilerplate filtering, static routing, prefix matching, prefix exclusions,
    apply_filter labels, integration, is_pnpm_script)
  • 4 Clap parsing tests (basic, with args, colon script, shorthand falls to Other)
  • cargo fmt --all && cargo clippy --all-targets && cargo test --all — 437 tests pass
  • Manual test with real pnpm project: rtk pnpm run test, rtk pnpm test, rtk pnpm run lint

Route pnpm scripts to specialized filters (vitest, tsc, eslint, prettier,
playwright) via static name matching and package.json auto-detection.
Supports both `rtk pnpm run test` and `rtk pnpm test` shorthand.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@pszymkowiak
Copy link
Collaborator

Review: PR #232

Thanks for this PR — great initiative! The two-tier routing design (static name matching + package.json detection) is clean and the FilterRoute enum is well-structured. I checked out the branch, built the release binary, and tested against a real pnpm project. Here are the findings.

Local test results (14 commands)

Test Result Bug?
rtk pnpm run test (vitest, all pass) 📊 OUTPUT (last 5 lines): + raw vitest output Yes — vitest filter never applied
rtk pnpm test (shorthand) Same raw output Yes — same bug
rtk pnpm run test (with failure) 100% raw output + ANSI codes Yes — no filtering at all
rtk pnpm run lint (no errors) ✓ Lint: No issues found OK
rtk pnpm run lint (with errors) Correctly filtered OK
rtk pnpm run build Clean output OK
rtk pnpm run dev Clean output OK
rtk pnpm list / outdated Working (existing) OK
rtk pnpm install ok ✓ OK
rtk pnpm store prune Passthrough OK OK
rtk pnpm dlx cowsay hello Passthrough OK OK
rtk pnpm exec vitest --version Runs "exec" script instead of pnpm exec Yes — native subcommand intercepted
rtk pnpm audit Runs "audit" script instead of pnpm audit Yes — native subcommand intercepted
rtk pnpm run test (outside node project) ok ✓ with exit code 1 Yes — misleading success message on failure

Comparison — rtk vitest run (existing filter) vs rtk pnpm run test (this PR):

$ rtk vitest run          → PASS (2) FAIL (0)          # ✅ compact
$ rtk pnpm run test       → 📊 OUTPUT (last 5 lines):  # ❌ raw fallback
                              ✓ src/index.test.ts (2 tests) 2ms
                              Test Files  1 passed (1)
                              ...

The main selling point of this PR (smart routing to vitest/playwright filters) doesn't work in practice.

Bugs to fix

1. Vitest/Playwright filter routing is broken

rtk pnpm run test falls through to the generic "last N lines" fallback instead of routing through VitestParser. This is likely caused by stdout/stderr concatenation (format!("{}\n{}", stdout, stderr)) — pnpm writes boilerplate to stderr, vitest writes JSON to stdout. Concatenating them before passing to VitestParser::parse() breaks JSON extraction.

Fix: Apply filter_pnpm_run_output() to stderr only, pass stdout separately to the specialized filter.

2. is_pnpm_script() intercepts native pnpm subcommands

Reproduced: added "exec": "echo exec script" and "audit": "echo audit script" to package.json. Then:

  • rtk pnpm exec vitest --version → runs the "exec" script instead of pnpm exec
  • rtk pnpm audit → runs the "audit" script instead of pnpm audit

Fix: Add a denylist of known pnpm native subcommands (exec, dlx, create, patch, audit, why, link, unlink, rebuild, store, setup, init, publish, pack, config, doctor) in is_pnpm_script() before checking package.json.

3. ok ✓ with exit 1 outside a node project

rtk pnpm run test from a directory without package.json shows ok ✓ but exits 1. The boilerplate filter strips pnpm's error message, leaving a misleading success indicator for a failed command.

Fix: On non-zero exit, don't apply the boilerplate filter — show the raw error output.

Other items

  • catch_unwind in apply_filter(): Replace with Result-based fallback — catch_unwind is for FFI/thread isolation, not application error handling
  • Double package.json read: is_pnpm_script() reads it at dispatch time, then detect_tool_from_package_json() reads it again. Consolidate into one read.
  • Token savings test at 40%: Project standard is 60% minimum
  • extract_test_summary(output, "npm test") hardcodes wrong label: Will always trigger Jest-style parsing regardless of actual runner
  • lazy_static! inside function: Move to module level to match RTK conventions

What works well

  • Lint routing works correctly (tested with real ESLint errors)
  • Build/dev script routing works
  • Existing pnpm commands (list, outdated, install) are not broken
  • Native pnpm subcommands (store prune, dlx, add) correctly passthrough
  • pub(crate) promotions are minimal and appropriate
  • Exit code preservation works on the filtered paths
  • 437 tests pass, build compiles

Thanks for the solid work — keep it up! Happy to re-review once the vitest routing and subcommand interception are fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants